home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Mac / Lib / cfmfile.py < prev    next >
Encoding:
Python Source  |  2000-06-23  |  4.5 KB  |  187 lines

  1. """codefragments.py -- wrapper to modify code fragments."""
  2.  
  3. # © 1998, Just van Rossum, Letterror
  4.  
  5. __version__ = "0.8b3"
  6. __author__ = "jvr"
  7.  
  8. import macfs
  9. import struct
  10. import Res
  11. import os
  12. import sys
  13.  
  14. DEBUG = 0
  15.  
  16. error = "cfm.error"
  17.  
  18. BUFSIZE = 0x80000
  19.  
  20. def mergecfmfiles(srclist, dst, architecture = 'fat'):
  21.     """Merge all files in srclist into a new file dst. 
  22.     
  23.     If architecture is given, only code fragments of that type will be used:
  24.     "pwpc" for PPC, "m68k" for cfm68k. This does not work for "classic"
  25.     68k code, since it does not use code fragments to begin with.
  26.     If architecture is None, all fragments will be used, enabling FAT binaries.
  27.     """
  28.     
  29.     srclist = list(srclist)
  30.     for i in range(len(srclist)):
  31.         if type(srclist[i]) == macfs.FSSpecType:
  32.             srclist[i] = srclist[i].as_pathname()
  33.     if type(dst) == macfs.FSSpecType:
  34.         dst = dst.as_pathname()
  35.     
  36.     dstfile = open(dst, "wb")
  37.     rf = Res.OpenResFile(dst)
  38.     try:
  39.         dstcfrg = CfrgResource()
  40.         for src in srclist:
  41.             srccfrg = CfrgResource(src)
  42.             for frag in srccfrg.fragments:
  43.                 if frag.architecture == 'pwpc' and architecture == 'm68k':
  44.                     continue
  45.                 if frag.architecture == 'm68k' and architecture == 'pwpc':
  46.                     continue
  47.                 dstcfrg.append(frag)
  48.                 
  49.                 frag.copydata(dstfile)
  50.                 
  51.         cfrgres = Res.Resource(dstcfrg.build())
  52.         Res.UseResFile(rf)
  53.         cfrgres.AddResource('cfrg', 0, "")
  54.     finally:
  55.         dstfile.close()
  56.         rf = Res.CloseResFile(rf)
  57.  
  58.  
  59. class CfrgResource:
  60.     
  61.     def __init__(self, path = None):
  62.         self.version = 1
  63.         self.fragments = []
  64.         self.path = path
  65.         if path is not None and os.path.exists(path):
  66.             currentresref = Res.CurResFile()
  67.             resref = Res.OpenResFile(path)
  68.             Res.UseResFile(resref)
  69.             try:
  70.                 try:
  71.                     data = Res.Get1Resource('cfrg', 0).data
  72.                 except Res.Error:
  73.                     raise Res.Error, "no ‘cfrg’ resource found", sys.exc_traceback
  74.             finally:
  75.                 Res.CloseResFile(resref)
  76.                 Res.UseResFile(currentresref)
  77.             self.parse(data)
  78.             if self.version <> 1:
  79.                 raise error, "unknown 'cfrg' resource format"    
  80.     
  81.     def parse(self, data):
  82.         (res1, res2, self.version, 
  83.             res3, res4, res5, res6, 
  84.             self.memberCount) = struct.unpack("8l", data[:32])
  85.         data = data[32:]
  86.         while data:
  87.             frag = FragmentDescriptor(self.path, data)
  88.             data = data[frag.memberSize:]
  89.             self.fragments.append(frag)
  90.     
  91.     def build(self):
  92.         self.memberCount = len(self.fragments)
  93.         data = struct.pack("8l", 0, 0, self.version, 0, 0, 0, 0, self.memberCount)
  94.         for frag in self.fragments:
  95.             data = data + frag.build()
  96.         return data
  97.     
  98.     def append(self, frag):
  99.         self.fragments.append(frag)
  100.  
  101.  
  102. class FragmentDescriptor:
  103.     
  104.     def __init__(self, path, data = None):
  105.         self.path = path
  106.         if data is not None:
  107.             self.parse(data)
  108.     
  109.     def parse(self, data):
  110.         self.architecture = data[:4]
  111.         (    self.updatelevel, 
  112.             self.currentVersion, 
  113.             self.oldDefVersion, 
  114.             self.stacksize,
  115.             self.applibdir, 
  116.             self.fragtype,
  117.             self.where,
  118.             self.offset,
  119.             self.length,
  120.             self.res1, self.res2,
  121.             self.memberSize,) = struct.unpack("4lhBB4lh", data[4:42])
  122.         pname = data[42:self.memberSize]
  123.         self.name = pname[1:1+ord(pname[0])]
  124.     
  125.     def build(self):
  126.         data = self.architecture
  127.         data = data + struct.pack("4lhBB4l",
  128.                 self.updatelevel, 
  129.                 self.currentVersion, 
  130.                 self.oldDefVersion, 
  131.                 self.stacksize,
  132.                 self.applibdir, 
  133.                 self.fragtype,
  134.                 self.where,
  135.                 self.offset,
  136.                 self.length,
  137.                 self.res1, self.res2)
  138.         self.memberSize = len(data) + 2 + 1 + len(self.name)
  139.         # pad to 4 byte boundaries
  140.         if self.memberSize % 4:
  141.             self.memberSize = self.memberSize + 4 - (self.memberSize % 4)
  142.         data = data + struct.pack("hb", self.memberSize, len(self.name))
  143.         data = data + self.name
  144.         data = data + '\000' * (self.memberSize - len(data))
  145.         return data
  146.     
  147.     def getfragment(self):
  148.         if self.where <> 1:
  149.             raise error, "can’t read fragment, unsupported location"
  150.         f = open(self.path, "rb")
  151.         f.seek(self.offset)
  152.         if self.length:
  153.             frag = f.read(self.length)
  154.         else:
  155.             frag = f.read()
  156.         f.close()
  157.         return frag
  158.     
  159.     def copydata(self, outfile):
  160.         if self.where <> 1:
  161.             raise error, "can’t read fragment, unsupported location"
  162.         infile = open(self.path, "rb")
  163.         if self.length == 0:
  164.             infile.seek(0, 2)
  165.             self.length = infile.tell()
  166.         
  167.         # Position input file and record new offset from output file
  168.         infile.seek(self.offset)
  169.         
  170.         # pad to 16 byte boundaries
  171.         offset = outfile.tell()
  172.         if offset % 16:
  173.             offset = offset + 16 - (offset % 16)
  174.         outfile.seek(offset)
  175.         self.offset = offset
  176.         
  177.         l = self.length
  178.         while l:
  179.             if l > BUFSIZE:
  180.                 outfile.write(infile.read(BUFSIZE))
  181.                 l = l - BUFSIZE
  182.             else:
  183.                 outfile.write(infile.read(l))
  184.                 l = 0
  185.         infile.close()
  186.  
  187.